package se.webbzon.boltzmann.battle.group;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import se.webbzon.boltzmann.battle.object.npc.BattleNPC;
import se.webbzon.boltzmann.battle.property.BattleBuff;
import se.webbzon.boltzmann.battle.property.BattleProperty;
import se.webbzon.boltzmann.battle.property.BattlePropertyListener;
import se.webbzon.boltzmann.battle.strategy.AbstractStrategy;

public class BattleGroup {
	
	// The id of the faction
	private final int factionId;
	
	// The id of the group
	private final int groupId;
	
	// A collection of all the listeners to this battle group
	private final Collection<BattleGroupListener> listeners;
	
	// The participants in this battle group
	private final List<BattleNPC> participants;
	
	// A battle property listener used to listen to defeated participants
	private final BattlePropertyListener listener;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new battle group with a given faction id and a group id. 
	 * Groups with the same faction id are allied in 
	 * battles. The group is if used to track spawn points but does not effect
	 * the outcome of the battle. The faction id must be a positive integer. **/
	public BattleGroup(int factionId, int groupId) {
		this.factionId = (factionId < 0) ? 0 : factionId;
		this.groupId = groupId;
		this.participants = new ArrayList<BattleNPC>();
		listeners = new ArrayList<BattleGroupListener>();
		listener = new Listener(this);
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the id of the faction associated with this battle group.
	 * Allied groups has the same faction id. **/
	public int getFactionId() {
		return factionId;
	}
	
	/** Returns the id of the group. **/
	public int getGroupId() {
		return groupId;
	}
	
	/** Adds a listener to this battle group. **/
	public boolean addListener(BattleGroupListener listener) {
		return listeners.add(listener);
	}
	
	/** Removes a listener to this battle group. **/
	public boolean removeListener(BattleGroupListener listener) {
		return listeners.remove(listener);
	}
	
	/** Clears all listeners in this battle group. **/
	public void clearListener(BattleGroupListener listener) {
		listeners.clear();
	}
	
	/** Returns the number of participants in this battle group. **/
	public int participants() {
		return participants.size();
	}
	
	/** Adds a participant to this group. **/
	public boolean addParticipant(BattleNPC participant) {
		if (participants.add(participant)) {
			participant.getProperty().addListener(listener);
			for (BattleGroupListener listener : listeners)
				listener.onAddParticipant(this,participant);
			return true;
		}
		return false;
	}
	
	/** Removes a participant from this group. **/
	public boolean removeParticipant(BattleNPC participant) {
		if (participants.remove(participant)) {
			participant.getProperty().removeListener(listener);
			for (BattleGroupListener listener : listeners)
				listener.onRemoveParticipant(this,participant);
			return true;
		}
		return false;
	}
	
	/** Returns the (n+1):th participant in this group. **/
	public BattleNPC getParticipant(int n) {
		return participants.get(n);
	}
	
	/** Returns a list of all participants in this battle group. **/
	public List<BattleNPC> getParticipants() {
		return Collections.unmodifiableList(participants);
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	private static final class Listener implements BattlePropertyListener {
		
		// The battle group associated with this listener
		private final BattleGroup battleGroup;
		
		/*============================================================
		Constructors
		============================================================*/
		
		/** Creates a new implemented BattlePropertyListener. **/
		public Listener(BattleGroup battleGroup) {
			this.battleGroup = battleGroup;
		}
		
		/*============================================================
		Public Methods
		============================================================*/

		@Override public void onSetMaxHealth(BattleProperty property, int maxHealth) {};

		@Override public void onSetHealth(BattleProperty property, int health) {
			if (health == 0) {
				BattleNPC participant = null;
				for (BattleNPC p : battleGroup.getParticipants()) {
					if (p.getProperty() == property) {
						participant = p;
						break;
					}
				}
				
				// Removes the defeated participant
				if (participant != null)
					battleGroup.removeParticipant(participant);
			}
		}

		@Override public void onSetMaxEnergy(BattleProperty property, int maxEnergy) {};

		@Override public void onSetEnergy(BattleProperty property, int energy) {};

		@Override public void onSetStrategy(BattleProperty property,
											AbstractStrategy strategy) {};

		@Override public void onBuffAdd(BattleProperty property, BattleBuff buff) {};

		@Override public void onBuffRemove(BattleProperty property, BattleBuff buff) {};
		
	}

}
